﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Threading;

namespace A2DFramework.CacheService.CacheProvider.LocalCache.LRU
{
    public class LRUCacheContainer : BaseCacheContainer
    {
        public LRUCacheContainer(int capacity)
            : base()
        {
            dic = new ConcurrentDictionary<object, BaseCacheItem>(2, capacity);
            this.capacity = capacity;
        }

        public override object Get(object key)
        {
            BaseCacheItem baseItem;
            if (!this.dic.TryGetValue(key, out baseItem))
                return null;

            if (baseItem == null)
                return null;

            LRUCacheItem item = (LRUCacheItem)baseItem;

            item.LatestTouchTime = DateTime.Now;
            return item.Value;
        }

        public override void Set(object key, object value, CacheExpireType expireType, DateTime absolutelyExpireTime, TimeSpan slideIncrement)
        {
            BaseCacheItem baseItem;
            if (this.dic.TryGetValue(key, out baseItem))
            {
                LRUCacheItem item = (LRUCacheItem)baseItem;
                item.Key = key;
                item.Value = value;
                item.LatestTouchTime = DateTime.Now;
                item.ExpireTime = absolutelyExpireTime;
                item.ExpireType = expireType;
                item.SlideIncrement = slideIncrement;
                return;
            }

            if (this.dic.Count >= this.capacity)
            {
                //remove one
                BaseCacheItem oldestTouchItem = GetOldestTouchItem();
                if (oldestTouchItem!=null)
                    this.dic.TryRemove(oldestTouchItem.Key, out oldestTouchItem);
            }

            {
                LRUCacheItem item = new LRUCacheItem();
                item.Key = key;
                item.Value = value;
                item.LatestTouchTime = DateTime.Now;
                item.ExpireTime = absolutelyExpireTime;
                item.ExpireType = expireType;
                item.SlideIncrement = slideIncrement;
                this.dic.TryAdd(key, item);
            }
        }

        private LRUCacheItem GetOldestTouchItem()
        {
            LRUCacheItem oldestTouch = null;
            foreach (var key in this.dic.Keys)
            {
                BaseCacheItem baseItem;
                if (!this.dic.TryGetValue(key, out baseItem))
                    continue;

                LRUCacheItem current = (LRUCacheItem)baseItem;
                if (oldestTouch == null)
                {
                    oldestTouch = current;
                    continue;
                }
                if (oldestTouch.LatestTouchTime > current.LatestTouchTime)
                    oldestTouch = current;
            }
            return oldestTouch;
        }

        public override void Remove(object key)
        {
            if (this.dic.ContainsKey(key))
            {
                BaseCacheItem item=new LRUCacheItem();
                this.dic.TryRemove(key, out item);
            }
        }
    }
}
